/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.skatiger.jrove.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.el.ELContext;
import javax.el.ELContextEvent;
import javax.el.ELContextListener;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;

import org.skatiger.jrove.ExternalContext;
import org.skatiger.jrove.ResponseWriter;
import org.skatiger.jrove.ViewContext;
import org.skatiger.jrove.component.UIComponent;
import org.skatiger.jrove.component.UIViewRoot;
import org.skatiger.jrove.el.JroveELContext;
import org.skatiger.jrove.renderer.Renderer;
import org.skatiger.jrove.util.AssertUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultViewContext extends ViewContext {
    private static final Logger logger = LoggerFactory
            .getLogger(DefaultViewContext.class);
    private DefaultConfigurator _configurator;
    private ExpressionFactory _expressionFactory;
    private ExternalContext _externalContext;
    private JroveELContext _elcontext;
    private ResponseWriter _responseWriter = null;
    private UIViewRoot _viewRoot;
    private Map<String, Object> _attributes;
    private boolean _complete = false;
    private boolean _released = false;

    public DefaultViewContext(final DefaultConfigurator configurator,
            ExternalContext externalContext) {
        _configurator = configurator;
        _expressionFactory = _configurator.getExpressionFactory();
        _attributes = new HashMap<String, Object>();
        ViewContext.setCurrentInstance(this);
        this._externalContext = externalContext;
    }

    @Override
    public Map<String, Object> getAttributes() {
        return _attributes;
    }

    public ExpressionFactory getExpressionFactory() {
        return _expressionFactory;
    }

    public Object getAttribute(String key) {
        return _attributes.get(key);
    }

    public Iterator<String> getAttributeNames() {
        return _attributes.keySet().iterator();
    }

    public DefaultConfigurator getConfigurator() {
        return _configurator;
    }

    public ELContext getELContext() {
        if (_elcontext != null) {
            return _elcontext;
        }
        buildELContext();

        return _elcontext;
    }

    public boolean isCompleted() {
        return _complete;
    }

    public ResponseWriter getResponseWriter() {
        return _responseWriter;
    }

    public UIViewRoot getViewRoot() {
        return _viewRoot;
    }

    public final void release() {
        if (_released) {
            throw new IllegalStateException("ViewContext already released");
        }
        _configurator = null;
        _responseWriter = null;
        _viewRoot = null;
        _elcontext = null;
        ViewContext.setCurrentInstance(null);
        _released = true;
        if (logger.isDebugEnabled()) {
            logger.debug("current Thread ViewContext released at " + new Date());
        }
    }

    public void removeAttribute(String key) {
        _attributes.remove(key);
    }

    public void complete() {
        _complete = true;
    }

    public void setAttribute(String key, Object value) {
        AssertUtil.notEmpty(key, "Attribute's name can not be null.");
        _attributes.put(key, value);
    }

    public void setResponseWriter(ResponseWriter writer) {
        _responseWriter = writer;
    }

    public void setViewRoot(UIViewRoot root) {
        _viewRoot = root;
    }

    @Override
    public UIComponent createComponent(String componentClass) {
        return getConfigurator().getComponentProvider().createComponent(this,
                componentClass);
    }

    @Override
    public Renderer getRenderer(String rendererType) {
        return getConfigurator().getRendererProvider().getRenderer(this,
                rendererType);
    }

    @Override
    public ValueExpression createValueExpression(String expression) {
        ValueExpression ve = getExpressionFactory().createValueExpression(
                expression, Object.class);
        return ve;
    }

    @Override
    public Object getExpressionValue(String expression) {
        ValueExpression ve = createValueExpression(expression);
        return ve.getValue(this._elcontext);
    }

    void buildELContext() {
        JroveELContext _elContext = new JroveELContext(this);
        ELContextEvent event = new ELContextEvent(_elContext);
        for (ELContextListener listener : _configurator.getELContextListeners()) {
            listener.contextCreated(event);
        }
        this._elcontext = _elContext;
    }

    @Override
    public void appendELResolver(ELResolver resolver) {
        _elcontext.appendELResolver(resolver);
    }

    @Override
    public ExternalContext getExternalContext() {
        return _externalContext;
    }
}
